package com.zenika.zenbinding.client.widget;

import java.util.List;

import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.zenika.zenbinding.client.ZenBinder;
import com.zenika.zenbinding.client.converter.Converter;
import com.zenika.zenbinding.client.converter.EnumConverter;
import com.zenika.zenbinding.client.converter.Radio2BooleanConverter;
import com.zenika.zenbinding.client.handler.ListBindingHandler;
import com.zenika.zenbinding.client.model.BusinessObject;
import com.zenika.zenbinding.client.model.ListModel;
import com.zenika.zenbinding.client.model.ValueModel;
import com.zenika.zenbinding.client.model.ZenEnum;

public class VerticalUserFormPanel extends Grid {
  
  private final static int DEFAULT_COLUMNS_PER_INPUT = 2;
  
  protected int nbColumnsPerInputColumn;
  protected int currentInputRow;
  
  /**
   * FIXME provide a default implementation with two columns with a special build() method that splits the fields between the two columns automatically. FIXME also create an implementation using
   * FlexTable
   */
  public VerticalUserFormPanel(int nbInputRows) {
    this(nbInputRows, DEFAULT_COLUMNS_PER_INPUT);
  }
  
  protected VerticalUserFormPanel(int nbInputRows, int nbColumnsPerInputColumn) {
    super(nbInputRows, nbColumnsPerInputColumn);
    // FIXME DEBUG
    this.setBorderWidth(1);
    this.currentInputRow = 0;
    this.nbColumnsPerInputColumn = nbColumnsPerInputColumn;
  }
  
  public ValueModel addTextBox(BusinessObject object, String property, String label) {
    Label associatedLabel = new Label(label);
    TextBox textBox = new TextBox();
    
    ValueModel valueModel = ZenBinder.bindValue(textBox, object, property);
    this.addEntryToPanel(associatedLabel, textBox);
    return valueModel;
  }
  
  public ValueModel addTextArea(BusinessObject object, String property, String label) {
    Label associatedLabel = new Label(label);
    
    TextArea textArea = new TextArea();
    ValueModel valueModel = ZenBinder.bindValue(textArea, object, property);
    this.addEntryToPanel(associatedLabel, textArea);
    return valueModel;
  }
  
  public ValueModel addCheckBox(BusinessObject object, String property, String label) {
    Label associatedLabel = new Label(label);
    CheckBox checkBox = new CheckBox();
    
    ValueModel valueModel = ZenBinder.bindValue(checkBox, object, property);
    this.addEntryToPanel(associatedLabel, checkBox);
    return valueModel;
  }
  
  public ListModel addRadioGroup(BusinessObject businessObject, String property, List<BusinessObject> businessObjects, String propertyInList, String label, boolean isVertical) {
    
    BusinessObject[] businessObjectsArray = businessObjects.toArray(new BusinessObject[businessObjects.size()]);
    return this.addRadioGroup(businessObject, property, businessObjectsArray, label, isVertical);
  }
  
  public ListModel addRadioGroup(BusinessObject businessObject, String property, BusinessObject[] businessObjects, String propertyInArray, String label, boolean isVertical) {
    
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    RadioGroup radioGroup = new RadioGroup(isVertical);
    
    ListBindingHandler handler = ZenBinder.createListBindingHandler(radioGroup, businessObjects, propertyInArray);
    return this.addRadioGroup(businessObject, property, handler, radioGroup, associatedLabel);
  }
  
  public ListModel addRadioGroup(BusinessObject businessObject, String property, List<?> choices, String label, boolean isVertical) {
    
    Object[] choicesArray = choices.toArray(new Object[choices.size()]);
    return this.addRadioGroup(businessObject, property, choicesArray, label, isVertical);
  }
  
  public ListModel addRadioGroup(BusinessObject businessObject, String property, Object[] choices, String label, boolean isVertical) {
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    RadioGroup radioGroup = new RadioGroup(isVertical);
    
    ListBindingHandler handler = ZenBinder.createListBindingHandler(radioGroup, choices);
    return this.addRadioGroup(businessObject, property, handler, radioGroup, associatedLabel);
  }
  
  public ListModel addBooleanRadioGroup(BusinessObject businessObject, String property, String[] choices, String label, boolean isVertical) {
    
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    RadioGroup radioGroup = new RadioGroup(isVertical);
    
    ListBindingHandler handler = ZenBinder.createListBindingHandler(radioGroup, choices);
    return this.addRadioGroup(businessObject, property, handler, radioGroup, associatedLabel, new Radio2BooleanConverter(choices));
  }
  
  private ListModel addRadioGroup(BusinessObject businessObject, String property, ListBindingHandler handler, RadioGroup radioGroup, Label associatedLabel) {
    return this.addRadioGroup(businessObject, property, handler, radioGroup, associatedLabel, null);
  }
  
  private ListModel addRadioGroup(BusinessObject businessObject, String property, ListBindingHandler handler, RadioGroup radioGroup, Label associatedLabel, Converter converter) {
    
    ListModel listModel = ZenBinder.bindList(handler, businessObject, property, converter);
    
    this.addEntryToPanel(associatedLabel, radioGroup);
    return listModel;
  }
  
  public ListModel addListBox(BusinessObject businessObject, String property, BusinessObject[] businessObjects, String propertyInArray, String label) {
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    ListBox listBox = new ListBox();
    
    ListModel listModel = ZenBinder.bindListBox(listBox, businessObject, property, businessObjects, propertyInArray);
    
    this.addEntryToPanel(associatedLabel, listBox);
    
    return listModel;
  }
  
  public ListModel addListBox(BusinessObject businessObject, String property, Object[] choices, String label) {
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    ListBox listBox = new ListBox();
    
    ListModel listModel = ZenBinder.bindListBox(listBox, businessObject, property, choices);
    
    this.addEntryToPanel(associatedLabel, listBox);
    
    return listModel;
  }
  
  public ListModel addListBox(BusinessObject businessObject, String property, List<?> choices, String label) {
    
    Object[] choicesArray = (Object[]) choices.toArray(new Object[choices.size()]);
    
    return this.addListBox(businessObject, property, choicesArray, label);
  }
  
  public ListModel addEnumListBox(BusinessObject businessObject, String property, ZenEnum[] choices, String label) {
    
    Label associatedLabel = null;
    if ( label != null )
      associatedLabel = new Label(label);
    ListBox listBox = new ListBox();
    
    ListBindingHandler handler = ZenBinder.createListBindingHandler(listBox, choices);
    ListModel listModel = ZenBinder.bindList(handler, businessObject, property, new EnumConverter(choices));
    
    this.addEntryToPanel(associatedLabel, listBox);
    
    return listModel;
  }
  
  public ListModel addListBox(BusinessObject businessObject, String property, List<BusinessObject> businessObjects, String propertyInList, String label) {
    BusinessObject[] businessObjectArray = businessObjects.toArray(new BusinessObject[businessObjects.size()]);
    return this.addListBox(businessObject, property, businessObjectArray, propertyInList, label);
  }
  
  private void addEntryToPanel(Label label, Widget widget) {
    // add the label
    int column = 0;
    System.out.println("(" + this.currentInputRow + "," + column + ") = " + label);
    if ( label != null )
      this.setWidget(this.currentInputRow, column, label);
    
    // add the input widget
    column++;
    System.out.println("(" + this.currentInputRow + "," + column + ") = " + widget);
    this.setWidget(this.currentInputRow, column, widget);
    
    // go to the next row
    this.currentInputRow++;
  }
  
}
